package com.jxlc.framework.web.service;

import com.jxlc.common.constant.Constants;
import com.jxlc.common.core.domain.model.BaseLoginUser;
import com.jxlc.common.core.domain.model.LoginUser;
import com.jxlc.common.core.redis.TokenRedisCache;
import com.jxlc.common.utils.ServletUtils;
import com.jxlc.common.utils.StringUtils;
import com.jxlc.framework.manager.AsyncManager;
import com.jxlc.framework.manager.factory.AsyncFactory;
import com.jxlc.framework.oauth2.domain.OAuth2AccessToken;
import com.jxlc.framework.oauth2.domain.OAuth2RefreshToken;
import com.jxlc.framework.oauth2.domain.dto.AccessTokenDto;
import com.jxlc.framework.oauth2.domain.dto.ClientCacheObj;
import com.jxlc.framework.oauth2.domain.dto.RefreshTokenDto;
import com.jxlc.framework.oauth2.service.FieldOAuth2AccessTokenService;
import com.jxlc.framework.oauth2.service.FieldOAuth2RefreshTokenService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Set;

import static com.jxlc.framework.oauth2.enums.LoginType.SYS;

/**
 * token验证处理
 *
 * @author jxlc
 */
@Component
public class SysTokenService
{

    // 令牌自定义标识
    @Value("${token.header}")
    private String header;

    // 令牌有效期（分钟）
    @Value("${token.expireTime}")
    private int expireTime;

    @Resource
    private TokenRedisCache tokenRedisCache;

    @Resource
    private FieldOAuth2RefreshTokenService oAuth2RefreshTokenService;

    @Resource
    private FieldOAuth2AccessTokenService oAuth2AccessTokenService;

    /**
     * 获取用户身份信息
     *
     * @return 用户信息
     */
    public LoginUser getLoginUser(HttpServletRequest request)
    {
        return getLoginUser(getHeaderToken(request));
    }

    /**
     * 获取用户身份信息
     *
     * @return 用户信息
     */
    public LoginUser getLoginUser(String token)
    {
        if (StringUtils.isNotEmpty(token)) {
            return tokenRedisCache.getToken(token);
        }
        return null;
    }

    /**
     * 获取第三方客户对象
     */
    public ClientCacheObj getLoginClient()
    {
        return tokenRedisCache.getToken(ServletUtils.getHeader(header));
    }

    /**
     * 获取第三方客户行政区划编码
     */
    public String getLoginDeptCode()
    {
        return getLoginClient().getDeptCode();
    }

    /**
     * 获取第三方客户密钥
     */
    public String getLoginSecret()
    {
        return getLoginClient().getSecret();
    }

    /**
     * 删除用户访问令牌缓存
     */
    public void delLoginUserCache(HttpServletRequest request)
    {
        String token = this.getHeaderToken(request);
        if (StringUtils.isEmpty(token)) {
            return;
        }
        tokenRedisCache.delToken(token);
        //删除访问令牌和刷新令牌
        this.delUserTokenCache(token);
    }

    /**
     * 删除访问令牌和刷新令牌
     */
    public void delUserTokenCache(String token) {
        if (StringUtils.isEmpty(token)) {
            return;
        }
        OAuth2AccessToken accessToken = oAuth2AccessTokenService.getByAccessToken(token);
        if (accessToken == null) {
            return;
        }
        oAuth2AccessTokenService.removeById(accessToken.getId());
        OAuth2RefreshToken refreshToken = oAuth2RefreshTokenService.getByRefreshToken(accessToken.getRefreshToken());
        if (refreshToken != null) {
            oAuth2RefreshTokenService.removeById(refreshToken.getId());
        }
    }

    /**
     * 获取请求token
     *
     */
    public String getHeaderToken(HttpServletRequest request)
    {
        String token = request.getHeader(header);
        if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX))
        {
            token = token.replace(Constants.TOKEN_PREFIX, "");
        }
        return token;
    }

    /**
     * 生成系统刷新令牌
     */
    public OAuth2RefreshToken createRefreshToken(Long userId){
        return createRefreshToken(userId, null);
    }

    /**
     * 生成系统刷新令牌
     */
    public OAuth2RefreshToken createRefreshToken(Long userId, Set<String> scopes){
        RefreshTokenDto refreshTokenDto = new RefreshTokenDto(SYS, expireTime * 7);
        refreshTokenDto.setUserId(userId);
        refreshTokenDto.setScopes(scopes);
        return oAuth2RefreshTokenService.createRefreshToken(refreshTokenDto);
    }

    /**
     * 生成系统访问令牌
     */
    public OAuth2AccessToken createAccessToken(OAuth2RefreshToken refreshToken, Object o){
        AccessTokenDto accessTokenDto = new AccessTokenDto(refreshToken.getLoginType(), expireTime, o);
        accessTokenDto.setUserId(refreshToken.getUserId());
        accessTokenDto.setScopes(refreshToken.getScopes());
        accessTokenDto.setRefreshToken(refreshToken.getRefreshToken());
        return oAuth2AccessTokenService.createToken(accessTokenDto);
    }

    /**
     * 获取访问令牌
     */
    public BaseLoginUser getAccessTokenFromCache(String token){
        if (this.hasSysTokenCache(token)) {
            return this.getSysTokenCache(token);
        }
        return null;
    }

    /**
     * 获取访问令牌
     */
    public OAuth2AccessToken getAccessToken(String token){
        return oAuth2AccessTokenService.getByAccessToken(token);
    }

    /**
     * redis缓存中是否含有访问令牌
     * */
    public boolean hasSysTokenCache(String token) {
        return tokenRedisCache.hasToken(token);
    }

    /**
     * 获取redis缓存中访问令牌
     */
    public <T> T getSysTokenCache(String token) {
        return tokenRedisCache.getToken(token);
    }

    /**
     * 访问令牌写入redis缓存中
     */
    public <T> void setSysTokenCache(final String token, final T value, final Integer timeout) {
        tokenRedisCache.setToken(token, value, timeout);
    }

    /**
     * 保存登出记录
     */
    public void saveLogoutRecord(final String token) {
        LoginUser loginUser = this.getLoginUser(token);
        if (loginUser == null) {
            return;
        }
        // 记录用户退出日志
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(loginUser.getUsername(), Constants.LOGOUT, "退出成功"));
    }
}
